import * as fse from "fs-extra";
import path from "path";
import * as xlsx from "xlsx";
import { projCfg } from '../../projCfg';
import { cmd_base } from './cmd_base';

/**
 * 目的：自动生成字段文件cfg.ts
 * 1 export const cfgName="cfgName";
 * 2 export interface ICfgName{
 *      /** 注释 *\/
 *      readonly xxx: number;
 * }
 * 3 获取表的方法
 */
export interface IHead {
    /** 使用的列 */
    useCol: number[];
    /** 注释 */
    note?: string[];
    /** 字段名 */
    fieldName: string[];
    /** 字段类型 */
    fieldType: string[];
    /** 下一行计算 */
    nextRow: number;
}
export class cmd_xlsx extends cmd_base {
    /** cfg.ts字符串 */
    xlsxCfgStr = "";
    /** idkey.ts字符串 */
    xlsxIdkeyStr = "";
    /** data.bin数据 */
    xlsxData = {};
    run() {
        let itself = this;
        let fileNames = fse.readdirSync(projCfg.xlsxSrcPath);
        for (let index = 0, len = fileNames.length; index < len; index++) {
            let fileName = fileNames[index];
            if (fileName.indexOf("~$") >= 0) {
                continue;//临时文件
            }
            let splitName = fileName.split(".");
            let nameSuffix = splitName[splitName.length - 1];
            if (nameSuffix != "xlsx" && nameSuffix != "xls") {
                continue;//非excel文件
            }
            let filePath = path.join(projCfg.xlsxSrcPath, fileName);
            itself.parserXlsx(filePath);
        }
        //写入cfg.ts文件
        itself.xlsxCfgStr = "export namespace cfg {\n" + itself.xlsxCfgStr;
        itself.xlsxCfgStr += "}"
        fse.ensureDirSync(projCfg.xlsxOutPath);
        fse.writeFile(path.join(projCfg.xlsxOutPath, "cfg.ts"), itself.xlsxCfgStr)
        //写入idkey.ts文件
        itself.xlsxIdkeyStr = `export namespace idKey{\n${itself.xlsxIdkeyStr}\n}`;
        fse.writeFile(path.join(projCfg.xlsxOutPath, "idkey.ts"), itself.xlsxIdkeyStr);
        //写入data.bin
        fse.writeJson(path.join(projCfg.xlsxOutPath, "data.bin"), itself.xlsxData);
    }
    /** 解析一个表 */
    parserXlsx(filePath: string) {
        let itself = this;
        let fileName = path.basename(filePath);
        let xlsxSplitName = fileName.split(".")[0].split("_")
        let xlsxName = xlsxSplitName[0];
        let xlsxNote = xlsxSplitName[1];
        if (xlsxName == "Formula") {
            //公式表
            itself.parserFormula(filePath, fileName)
            return;
        }
        let sheetName = "zhCN";
        let file = xlsx.readFile(filePath);
        let sheet = file.Sheets[sheetName];
        if (!sheet) {
            console.error(`${fileName}:没有名称为zhCN的Sheet,此为必填项!`);
            return;
        }
        let range = xlsx.utils.decode_range(sheet["!ref"]);
        let head = itself.parserHead(sheet, range, fileName, sheetName);
        if (!head) {
            return;
        }

        let colLen = head.useCol.length;
        /** xlsx的json数据 */
        let cfgJson = {};
        /** xlsx的Idkey数据 */
        let idkey = {};
        /** 检测id重复 */
        let idMap = {};
        /** 表格第二列是否配置key */
        let ishasKey = false;
        /** id的类型 */
        let cfgIdType = "";
        let dataJson = { field: {}, type: {}, data: {} };
        for (let index = 0; index < colLen; index++) {
            let col = head.useCol[index];
            let colStr = xlsx.utils.encode_col(col);
            dataJson.field[colStr] = head.fieldName[index];
            dataJson.type[colStr] = head.fieldType[index];
        }
        for (let row = head.nextRow; row < range.e.r; row++) {//行
            let cfgId = void 0;
            for (let index = 0; index < colLen; index++) {//列
                let col = head.useCol[index];
                let ref = xlsx.utils.encode_cell({ c: col, r: row });
                let data = sheet[ref] as xlsx.CellObject;
                let value = data?.w;
                let type = head.fieldType[index];
                let filedName = head.fieldName[index];
                if (index == 0) {//id列
                    if (value == void 0) {
                        break;
                    }
                    cfgId = value;
                    if (idMap[cfgId]) {
                        console.error(`${xlsxName}表id重复：${cfgId}}`);
                        break;
                    }
                    idMap[cfgId] = 1;
                    dataJson[cfgId] = {};
                    cfgIdType = type;
                }
                if (filedName == "key") {//key列
                    if (cfgId != "-1") {
                        ishasKey = true;
                        if (value == void 0) {
                            console.error(`${xlsxName}表${cfgId}没有配置key`);
                            return;
                        }
                        idkey[value] = cfgIdType == "string" ? `"${cfgId}"` : cfgId;
                    }
                }
                if (value == void 0) {
                    continue;
                }
                let json = cfgJson[cfgId] = cfgJson[cfgId] || {};
                json[filedName] = itself.getValue(value, type, `${xlsxName}表${ref})}类型不匹配`);
                let colStr = xlsx.utils.encode_col(col);
                dataJson[cfgId][colStr] = value;
            }
        }
        itself.xlsxData[xlsxName] = dataJson;
        //新写cfgJson文件
        let dir = path.join(projCfg.xlsxOutPath, "data")
        fse.ensureDirSync(dir);
        fse.writeJson(path.join(dir, `json${xlsxName}.json`), cfgJson);
        //写入每张表的接口声明
        itself.xlsxCfgStr += `\t/** ${xlsxNote} */\n`;
        itself.xlsxCfgStr += `\texport const ${xlsxName} = "${xlsxName}";\n`;
        itself.xlsxCfgStr += `\t/** ${xlsxNote} */\n`;
        itself.xlsxCfgStr += `\texport interface I${xlsxName} {\n`;
        for (let index = 0, len = head.fieldType.length; index < len; index++) {
            let note = head.note[index];
            let name = head.fieldName[index];
            let type = itself.getReadonlyType(head.fieldType[index]);
            if (note) {
                itself.xlsxCfgStr += `\t\t/** ${note} */\n`;
            }
            itself.xlsxCfgStr += `\t\treadonly ${name}?: ${type};\n`;
        }
        itself.xlsxCfgStr += `\t}\n`;
        //写入idKey.ts
        if (ishasKey) {
            itself.xlsxIdkeyStr += `\texport const enum ${xlsxName} {\n`
            for (let key in idkey) {
                itself.xlsxIdkeyStr += `\t\t${key} = ${idkey[key]},\n`;
            }
            itself.xlsxIdkeyStr += `\t}\n`
        }
    }
    /**
     * 取表头
     * @param sheet 表中某个页
     * @param range 范围
     * @param xlsxName 表名称
     * @param sheetName 页名称
     */
    parserHead(sheet: xlsx.WorkSheet, range: xlsx.Range, xlsxName: string, sheetName: string) {
        let itself = this;
        let firstRow = range.s.r;
        let firstCol = range.s.c;
        /** 跳过的列 */
        let breakCol = {};
        let useCol = [];
        let note: string[] = [];
        let fieldName: string[] = [];
        let filedType: string[] = [];
        let nextRow = 0;
        for (let row = firstRow; row < range.e.r; row++) {//行
            for (let col = firstCol; col < range.e.c; col++) {//列
                if (breakCol[col]) {
                    continue;
                }
                let ref = xlsx.utils.encode_cell({ c: col, r: row });
                let data = sheet[ref] as xlsx.CellObject;
                switch (row) {//行
                    case firstRow: {//cs
                        if (!data || !data.w || data.w.search(/c/i) < 0) {
                            breakCol[col] = 1;
                            continue;
                        }
                        useCol.push(col);
                    } break;
                    case firstRow + 1: {//注释
                        let value = data?.w || "";
                        note.push(value);
                    } break;
                    case firstRow + 2: {//字段
                        let value = data?.w;
                        if (!value) {
                            console.error(`表【${xlsxName}】【${sheetName}页${ref}处】没有配置字段`);
                            return;
                        }
                        fieldName.push(value);
                    } break;
                    case firstRow + 3: {//数据类型
                        let value = data?.w;
                        if (!value) {
                            console.error(`表【${xlsxName}】【${sheetName}页${ref}处】没有配置数据类型`);
                            return;
                        }
                        filedType.push(itself.getFieldType(value));
                    } break;
                    default: {//数据
                        nextRow = row;
                        return {
                            useCol: useCol,
                            note: note,
                            fieldName: fieldName,
                            fieldType: filedType,
                            nextRow: nextRow,
                        } as IHead;
                    } break;
                }

            }
        }
    }

    /**
     * 解析公式表
     * @param filePaht 表中某个页
     * @param fileName 
     */
    parserFormula(filePaht: string, fileName: string) {
        let itself = this;
        let sheetName = "zhCN";
        // let file = xlsx.readFile(filePaht);
        // let sheet = file.Sheets[sheetName];
        // let range = xlsx.utils.decode_range(filePaht["!ref"]);
        // let head = itself.parserHead(sheet, range, fileName, sheetName);
        // if (!head) {
        //     return;
        // }

    }
    /**
     * 获取对应类型的值  如果是数组：一维：|，二维：; |
     * @param value 
     * @param typeStr 
     * @param errStr 报错文本  xxx表xxx行xxx列
     */
    getValue(value: string, typeStr: string, errStr: string) {
        let length = typeStr.split("[]").length - 1;
        let type = typeStr.match(/[a-zA-Z]+/)[0];
        switch (length) {
            case 0: {
                if (type == "number") {
                    return +value;
                } else if (type == "boolean") {
                    return !!value;
                }
                return value;
            } break;
            case 1: {
                let valueArrOne = value.split("|");
                if (type == "string") {
                    return valueArrOne;
                }
                let arr = [];
                for (let index = 0, len = valueArrOne.length; index < len; index++) {
                    if (type == "number") {
                        let num = Number(valueArrOne[index]);
                        if (isNaN(num)) {
                            console.error(`转换数字错误：${errStr}`)
                            return [];
                        }
                        arr.push(num)
                    } else if (type == "boolean") {
                        arr.push(!!valueArrOne[index])
                    }
                }
                return arr;
            } break;
            case 2: {
                let arrValue = value.split(";");
                let tempValue = [];
                for (let indexTwo = 0; indexTwo < arrValue.length; indexTwo++) {
                    let arrValue2 = arrValue[indexTwo].split("|");
                    if (type == "string") {
                        tempValue.push(arrValue2);
                    } else {
                        let arr = [];
                        for (let index = 0, len = arrValue2.length; index < len; index++) {
                            if (type == "number") {
                                let num = Number(arrValue2[index]);
                                if (isNaN(num)) {
                                    console.error(`转换数字错误：${errStr}`)
                                    return [];
                                }
                                arr.push(num)
                            } else if (type == "boolean") {
                                arr.push(!!arrValue2[index])
                            }
                        }
                        tempValue.push(arr);
                    }
                }
                return tempValue;
            } break;
            default: {
                console.error("不支持3维以上数组")
                return [];
            } break;
        }
    }

}

new cmd_xlsx().run();